home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Just Call Me Internet
/
Just Call Me Internet.iso
/
prog
/
atari
/
c
/
zsource
/
rz.c
< prev
next >
Wrap
C/C++ Source or Header
|
1988-05-18
|
29KB
|
1,449 lines
/*
* ACKNOWLEDGEMENTS
*
* ZMDM was derived from rz/sz for Unix posted by
* Chuck Forsberg (...!tektronix!reed!omen!caf ). We
* thank him for his excellent code, and for giving
* us permission to use and distribute his code and
* documentation.
*
* Atari St version by:
* Jwahar Bammi
* usenet: mandrill!bammi@{decvax,sun}.UUCP
* csnet: bammi@mandrill.ces.CWRU.edu
* arpa: bammi@mandrill.ces.CWRU.edu
* CompuServe: 71515,155
*/
#include "config.h"
#define RVERSION "rz 1.14 01-15-87"
#define RSTVERSION "rz 1.01 03-07-87"
#define OS "Unix V7/BSD"
/* #define RDEBUG */ /* a lot of debugging garb */
/*
* ATARI ST series implementation notes:
*
* - the following command line options were removed as they
* were either not applicable to the ST environment or
* were not deemed reasonable (by me - ofcourse).
* 1 Not Applicable here as we have a seperate
* serial port.
* 7 In this day and age? Forget it, get another m/c.
* a/b Ascii/Binary - the receive mode (if not
* over-ridden by the sender) is automatically
* selected depending on the extention given
* in the incoming file name. This idea was
* present in earlier rz/sz, i wonder why such
* a convenient feature was dropped (Chuck ??).
* This feature is relevant to ZMODEM only in rz,
* as the sender determines the file mode in
* XMODEM/YMODEM transfers.
* B Note that `B' has a special meaning.
* Specifying -B will force override to
* binary mode for each incoming file. Useful
* when doing St-to-St transfers.
* D There is no /dev/null on the ST's
* u not applicable to TOS. Upper and lower
* case file names are the same. All the
* applicable routines like uncap() and
* IsAnyLower() were zapped.
*
* - The [-][v]rzCOMMAND style of invocation was dropped
* as there is no good way to do pipes without the
* microRtx kernal. All references to Pipe and popen()
* were zapped.
* - Verbose is always set to 2 by automatically, as we know that
* stdout != stderr. This can be overridden
* by specifying -q to ensure that Verbose = 0
* - The idea of a PUBDIR and Restricted paths in the origonal
* code was dropped totally as it is not applicable
* to the single owner ST environment. 1 man 1 machine.
* - CRCTABLE is default always, hey we have plenty of memory!.
* - LOGFILE renamed to 'rzlog/szlog' as we don't always have
* a meaningful environment to pick up TMPDIR from (like when
* running from the desktop).
* - When a subdirectory in an incoming path name is not
* present it is created.
* - The file mode transmitted is 0S00 where S is derived from
* the Read/Write attribute of the file on the ST
* - When a file mode is received, only the owner bits are
* are checked. If it was read only (r--) on the Unix sytem
* then it is given read only attribute on the ST, read-write
* otherwise.
* - Of course all the I/O was completely redone on the ST.
* - You will find two versions of VARARGS routines like log,
* one that takes int args, and the other that takes long
* (address) args, since sizeof(int) != sizeof(long)
* and sizeof(int) != sizeof(pointer) on the ST.
*
* ST v1.01
* added support for 32 bit CRC's for Zmodem ++jrb
*
* ST v1.2
* added -B ++jrb
* added all the recursive stuff
* added remote
*/
/*% cc -DNFGVMIN -DCRCTABLE -K -O % -o rz; size rz
*
* rz.c By Chuck Forsberg
*
* cc -O rz.c -o rz USG (3.0) Unix
* cc -O -DV7 rz.c -o rz Unix V7, BSD 2.8 - 4.3
*
* ln rz rb For either system
*
* ln rz /usr/bin/rzrmail For remote mail. Make this the
* login shell. rzrmail then calls
* rmail(1) to deliver mail.
*
* define CRCTABLE to use table driven CRC
*
* Unix is a trademark of Western Electric Company
*
* A program for Unix to receive files and commands from computers running
* Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
* rz uses Unix buffered input to reduce wasted CPU time.
*
* Iff the program is invoked by rzCOMMAND, output is piped to
* "COMMAND filename"
*
* Some systems (Venix, Coherent, Regulus) may not support tty raw mode
* read(2) the same way as Unix. ONEREAD must be defined to force one
* character reads for these systems. Added 7-01-84 CAF
*
* Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF
*
* NFGVMIN Added 1-13-85 CAF for PC-AT Xenix systems where c_cc[VMIN]
* doesn't seem to work (even though it compiles without error!).
*
* USG UNIX (3.0) ioctl conventions courtesy Jeff Martin
*/
#include "zmdm.h"
#include "common.h"
#include "zmodem.h"
static unsigned long SaveIntr;
#ifndef Vsync /* Atari forgot these in osbind.h */
#define Vsync() xbios(37)
#endif
#ifndef Supexec
/* Some versions of osbind don't define Supexec */
#define Supexec(X) xbios(38,X)
#endif
#if (MWC || MANX)
extern FILE *fopen();
#else
extern FILE *fopen(), *fopenb();
#endif
#ifndef STANDALONE
#define RETURN return
#else
int bibis() {} /* dummy */
#endif
static long start_time;
/* called by simulated signal interrupt or terminate to clean things up */
bibi(n)
int n;
{
if (Zmodem)
zmputs(Attn);
canit(); mode(0);
fprintf(STDERR, "\r\nrz: caught signal %d; exiting", n);
if (fout != -1)
{
if (stfclose(fout) != 0)
{
fprintf(STDERR, "\r\nfile close ERROR\n");
}
fout = (-1);
}
#ifdef RDEBUG
if (logf != (FILE *)NULL)
fclose(logf);
#endif
aexit(128+n);
}
#ifdef STANDALONE
main(argc, argv)
#else
dorz(argc, argv)
#endif /* STANDALONE */
int argc;
char **argv;
{
register char *cp;
register int npats;
char **patts;
int exitcode;
#ifdef STANDALONE
#if (MWC || MANX)
extern char *lmalloc();
#endif
/* Set up Dta */
Fsetdta(&statbuf);
/* Get screen rez */
rez = Getrez();
drv_map = Drvmap();
#if (MWC || MANX)
#ifndef DYNABUF
if((bufr = (unsigned char *)lmalloc((unsigned long)BBUFSIZ))
== (unsigned char *)NULL)
#else
if((bufr = dalloc()) == (unsigned char *)NULL)
#endif /* DYNABUF */
{
#ifdef REMOTE
Bauxws("Sorry, could not allocate enough memory\r\n");
#else
Bconws("Sorry, could not allocate enough memory\r\n");
#endif
Pterm(4);
}
#else /* MWC || MANX */
#ifdef DYNABUF
if((bufr = dalloc()) == (unsigned char *)NULL)
{
#ifdef REMOTE
Bauxws("Sorry, could not allocate enough memory\r\n");
#else
Bconws("Sorry, could not allocate enough memory\r\n");
#endif
Pterm(5);
}
#endif /* DYNABUF */
#endif /* MWC || MANX */
#ifndef REMOTE
STDERR = stderr;
#else
#ifndef DLIBS
if((STDERR = fopen("aux:", "rw")) == (FILE *)NULL)
{
Bauxws("Could not Open Aux Stream for Stderr\r\n");
finish();
}
setbuf(STDERR, (char *)NULL);
#else
STDERR = stdaux;
#endif /* DLIBS */
#endif /* REMOTE */
{
int speed;
speed = getbaud();
Baudrate = BAUD_RATE(speed);
SetIoBuf();
Rsconf(speed, 0,-1,-1,-1,-1);
Vsync(); Vsync();
}
#endif /* STANDALONE */
SendType = 0;
Rxtimeout = 100;
exitcode = 0;
initz();
#ifndef STANDALONE
chkinvok(argv[0]); /* if called as 'rb' set flag */
#else
Progname = "rz";
#endif
npats = 0;
SaveIntr = Setexc(0x0102, -1L);
BusErr = Setexc(2, -1L);
AddrErr = Setexc(3, -1L);
vdebug = 0;
while (--argc)
{
cp = *++argv;
if (*cp == '-')
{
while( *++cp)
{
switch(*cp)
{
case '+':
Lzmanag = ZMAPND; break;
case 'B':
ForceBinary=TRUE; break;
case 'c':
Crcflg=TRUE; break;
case 'p':
Lzmanag = ZMPROT; break;
case 'q':
Quiet=TRUE; Verbose=0; break;
case 't':
if (--argc < 1) {
rusage();
RETURN(1);
}
Rxtimeout = atoi(*++argv);
if (Rxtimeout<10 || Rxtimeout>1000)
{
rusage();
RETURN(1);
}
break;
case 'v':
++Verbose; break;
default:
rusage();
RETURN(1);
}
}
}
else if ( !npats && argc>0)
{
if (argv[0][0])
{
npats=argc;
patts=argv;
}
}
}
if (npats > 1)
{
rusage();
RETURN(1);
}
#ifdef RDEBUG
if (Verbose > 2)
{
if ((logf = fopen(RLOGFILE, "a"))== (FILE *)NULL)
{
fprintf(STDERR, "Can't open log file %s\n",RLOGFILE);
RETURN(0200);
}
fprintf(logf, "Progname=%s\n", Progname);
vdebug = 1;
}
#endif
if ( !Quiet)
{
if (Verbose == 0)
Verbose = 2;
}
Setexc(0x0102, bibi);
Setexc(2, buserr);
Setexc(3, addrerr);
if((exitcode = setjmp(abrtjmp)))
{
/* on Contrl-C */
canit();
Setexc(2, BusErr);
Setexc(3, AddrErr);
Setexc(0x0102, SaveIntr);
RETURN(exitcode);
}
if(setjmp(busjmp))
{
/* On a bus error - instead of 2 bombs */
fprintf(STDERR,"\r\nFATAL: Bus Error\n\n");
#ifdef RDEBUG
if(logf != (FILE *)NULL)
fclose(logf);
#endif
if(fout != -1)
{
if (stfclose(fout) != 0)
{
fprintf(STDERR, "\r\nfile close ERROR\n");
}
fout = (-1);
}
canit();
Setexc(2, BusErr);
Setexc(3, AddrErr);
Setexc(0x0102, SaveIntr);
RETURN(2);
}
if(setjmp(addrjmp))
{
/* On address error - instead of 3 bombs */
fprintf(STDERR,"\r\nFATAL: Address Error\n\n");
#ifdef RDEBUG
if(logf != (FILE *)NULL)
fclose(logf);
#endif
if(fout != -1)
{
if (stfclose(fout) != 0)
{
fprintf(STDERR, "\r\nfile close ERROR\n");
}
fout = (-1);
}
canit();
Setexc(2, BusErr);
Setexc(3, AddrErr);
Setexc(0x0102, SaveIntr);
RETURN(3);
}
mode(1);
if (wcreceive(npats, patts)==ERROR)
{
exitcode=0200;
canit();
}
mode(0);
if (exitcode && !Zmodem) /* bellow again with all thy might. */
canit();
#ifdef RDEBUG
if(logf != (FILE *)NULL)
fclose(logf);
#endif
if(fout != -1)
{
if (stfclose(fout) != 0)
{
fprintf(STDERR, "\r\nfile close ERROR\n");
}
fout = (-1);
}
Setexc(2, BusErr);
Setexc(3, AddrErr);
Setexc(0x0102, SaveIntr);
RETURN(exitcode);
}
#ifdef STANDALONE
RETURN(n)
int n;
{
ResetIoBuf();
#if (MWC || MANX)
#ifndef DYNABUF
free(bufr);
#else
Mfree(bufr);
#endif
#else
#ifdef DYNABUF
Mfree(bufr);
#endif
#endif
exit(n);
}
#endif /* STANDALONE */
rusage()
{
fprintf(STDERR,
"%s for %s by ST Enthusiasts at Case Western Reserve University\n",
RSTVERSION, STOS);
fprintf(STDERR, "\tBased on %s for %s by Chuck Forsberg\n\n",
RVERSION, OS);
fprintf(STDERR,"Usage: rz [-Bpqtv] (ZMODEM Batch)\n");
fprintf(STDERR,"or rb [-qtv] (YMODEM Batch)\n");
fprintf(STDERR,"or rz [-cqtv] file (XMODEM or XMODEM-1k)\n");
fprintf(STDERR," -B Force Binary Mode transfers\n");
fprintf(STDERR," -v Verbose more v's give more info\n");
fprintf(STDERR," -q Quiet suppresses verbosity\n");
fprintf(STDERR," -t TIM Change timeout to TIM tenths of seconds\n");
fprintf(STDERR," -c Use 16 bit CRC (XMODEM)\n");
fprintf(STDERR," -p Protect existing dest. file by skipping\n");
fprintf(STDERR," transfer if the dest. file exists (ZMODEM ONLY)\n\n");
if(fout != -1)
{
if (stfclose(fout) != 0)
{
fprintf(STDERR, "\r\nfile close ERROR\n");
}
fout = (-1);
}
#ifdef RDEBUG
if(logf != (FILE *)NULL)
fclose(logf);
#endif
return(1);
}
/*
* Let's receive something already.
*/
wcreceive(argc, argp)
int argc;
char **argp;
{
register int c;
if (Batch || argc==0)
{
Crcflg=(Wcsmask==0377);
if ( !Quiet)
#ifndef REMOTE
fprintf(STDERR, "\n%s: ready (CTRL-C to cancel)\n\n",
Progname);
#else
fprintf(STDERR, "\n%s: ready\n\n",
Progname);
#endif
if (c=tryz())
{
if (c == ZCOMPL)
return OK;
if (c == ERROR)
goto fubar;
c = rzfiles();
if (c)
goto fubar;
}
else
{
for (;;)
{
if (wcrxpn(secbuf)== ERROR)
goto fubar;
if (secbuf[0]==0)
return OK;
if (procheader(secbuf) == ERROR)
goto fubar;
if (wcrx()==ERROR)
goto fubar;
}
}
}
else
{
Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
strcpy(Pathname, *argp);
#ifndef REMOTE
fprintf(STDERR, "\n%s: ready to receive %s (CTRL-C to Cancel)\n\n",
Progname, Pathname);
#else
fprintf(STDERR, "\n%s: ready to receive %s\n\n",
Progname, Pathname);
#endif
#ifdef RDEBUG
if(logf != (FILE *)NULL)
fprintf(logf, "\nrz: ready to receive %s ", Pathname);
#endif
if((fout = stfopen(Pathname,"w")) <= 0)
return ERROR;
if (wcrx()==ERROR)
goto fubar;
}
return OK;
fubar:
canit();
if (fout != -1)
{
if (stfclose(fout) != 0)
{
fprintf(STDERR, "\r\nfile close ERROR\n");
}
fout = (-1);
}
return ERROR;
}
/*
* Fetch a pathname from the other end as a C ctyle ASCIZ string.
* Length is indeterminate as long as less than Blklen
* A null string represents no more files (YMODEM)
*/
wcrxpn(rpn)
char *rpn; /* receive a pathname */
{
register int c;
PURGELINE;
et_tu:
Firstsec=TRUE; Eofseen=FALSE;
sendline(Crcflg?WANTCRC:NAK);
Lleft=0; /* Do read next time ... */
while ((c = wcgetsec(rpn, 100)) != 0)
{
llog( "Pathname fetch returned %d\n", c);
if (c == WCEOT)
{
sendline(ACK);
Lleft=0; /* Do read next time ... */
readline(1);
goto et_tu;
}
return ERROR;
}
sendline(ACK);
return OK;
}
/*
* Adapted from CMODEM13.C, written by
* Jack M. Wierda and Roderick W. Hart
*/
wcrx()
{
register int sectnum, sectcurr;
register char sendchar;
int cblklen; /* bytes to dump this block */
Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
sendchar=Crcflg?WANTCRC:NAK;
for (;;)
{
sendline(sendchar); /* send it now, we're ready! */
Lleft=0; /* Do read next time ... */
sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
report(sectcurr);
if (sectcurr==(sectnum+1 &Wcsmask))
{
sectnum++;
cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
if (putsec(secbuf, cblklen)==ERROR)
return ERROR;
if ((Bytesleft-=cblklen) < 0)
Bytesleft = 0;
sendchar=ACK;
}
else if (sectcurr==(sectnum&Wcsmask))
{
log2( "Received dup Sector\n");
sendchar=ACK;
}
else if (sectcurr==WCEOT)
{
if (closeit(0L))
return ERROR;
sendline(ACK);
Lleft=0; /* Do read next time ... */
return OK;
}
else if (sectcurr==ERROR)
return ERROR;
else
{
log2( "Sync Error\n");
return ERROR;
}
}
}
/*
* Wcgetsec fetches a Ward Christensen type sector.
* Returns sector number encountered or ERROR if valid sector not received,
* or CAN CAN received
* or WCEOT if eot sector
* time is timeout for first char, set to 4 seconds thereafter
***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
* (Caller must do that when he is good and ready to get next sector)
*/
wcgetsec(rxbuf, maxtime)
char *rxbuf;
int maxtime;
{
register int checksum, wcj, firstch;
register unsigned int oldcrc;
register char *p;
int sectcurr;
for (Lastrx=errors=0; errors<RETRYMAX; errors++)
{
if ((firstch=readline(maxtime))==STX)
{
Blklen=KSIZE; goto get2;
}
if (firstch==SOH)
{
Blklen=SECSIZ;
get2:
sectcurr=readline(1);
if ((sectcurr+(oldcrc=readline(1)))==Wcsmask)
{
oldcrc=checksum=0;
for (p=rxbuf,wcj=Blklen; --wcj>=0; )
{
if ((firstch=readline(1)) < 0)
goto bilge;
oldcrc=updcrc(firstch, oldcrc);
checksum += (*p++ = firstch);
}
if ((firstch=readline(1)) < 0)
goto bilge;
if (Crcflg)
{
oldcrc=updcrc(firstch, oldcrc);
if ((firstch=readline(1)) < 0)
goto bilge;
oldcrc=updcrc(firstch, oldcrc);
if (oldcrc & 0xFFFF)
llog("CRC=0%o\n", oldcrc);
else
{
Firstsec=FALSE;
return sectcurr;
}
}
else if (((checksum-firstch)&Wcsmask)==0)
{
Firstsec=FALSE;
return sectcurr;
}
else
log2( "Checksum Error\n");
}
else
log2("Sector number garbled 0%o 0%o\n",
sectcurr, oldcrc);
}
/* make sure eot really is eot and not just mixmash */
else if (firstch==EOT && Lleft==0)
return WCEOT;
else if (firstch==CAN)
{
if (Lastrx==CAN)
{
log2( "Sender CANcelled\n");
return ERROR;
}
else
{
Lastrx=CAN;
continue;
}
}
else if (firstch==TIMEOUT)
{
if (Firstsec)
goto humbug;
bilge:
log2( "Timeout\n");
}
else
llog( "Got 0%o sector header\n", firstch);
humbug:
Lastrx=0;
while(readline(1)!=TIMEOUT)
;
if (Firstsec)
{
sendline(Crcflg?WANTCRC:NAK);
Lleft=0; /* Do read next time ... */
}
else
{
maxtime=40; sendline(NAK);
Lleft=0; /* Do read next time ... */
}
}
/* try to stop the bubble machine. */
canit();
return ERROR;
}
/*
* Process incoming file information header
*/
procheader(name)
char *name;
{
register char *p;
register int dot;
char openmode[4];
extern int strlen();
/* convert to ST style path names */
for( p = name; *p != '\0'; p++)
{
if(*p == '/')
*p = '\\';
}
/* pick out the last extention in the filename in each part of path */
while(p != name)
{
dot = 0; p-- ;
while((p != name) && (*p != '\\'))
{
if(*p == '.')
{
if(dot == 0)
{
dot = 1;
}
else
{
/* replace all but the last dot with '_' */
*p = '_';
}
}
p--;
}
}
/* set default parameters and overrides */
strcpy(openmode,"w");
Thisbinary = isbinary(name);
if (Lzmanag)
zmanag = Lzmanag;
/*
* Process ZMODEM remote file management requests
*/
if ( zconv == ZCNL) /* Remote ASCII override */
Thisbinary = 0;
if (zconv == ZCBIN) /* Remote Binary override */
++Thisbinary;
else if (zmanag == ZMAPND)
strcpy(openmode, "a");
if (ForceBinary == TRUE ) /* local binary force override */
++Thisbinary;
/* ZMPROT check for existing file */
if (zmanag == ZMPROT && existf(name, "r"))
{
return ERROR;
}
/* ATARI ST NOTE:
* We will not accept rooted paths ie. paths that begin in '\' or '.\'
* If the incoming filename is rooted, we skip the beginning
* '\' '.\' or '..\'
*/
if( (name[0] == '\\') || (name[0] == '.') )
{
/* skip over the leading stuff */
if(name[0] == '\\')
name = &name[1];
else
{
if(name[1] == '.')
name = &name[3]; /* Skip the "..\" */
else
name = &name[2]; /* Skip the ".\" */
}
}
/* ST addition, create any dierctories in the path that don't exist */
if( pathensure(name) == ERROR)
return ERROR;
Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
p = name + 1 + strlen(name);
if (*p)
{ /* file coming from Unix or DOS system */
sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
/* NA to atari
if (Filemode & UNIXFILE)
++Thisbinary;
*/
#ifndef REMOTE
if (Verbose)
{
fprintf(STDERR,
"\nIncoming:\n\tName:\t%s\n\tBytes:\t%ld\n\
\tModTime: %ld\n\tMode:\t%o\n\tBufSize: %ld\n\n",
name, Bytesleft, Modtime, Filemode, (long)BBUFSIZ);
#ifdef RDEBUG
if(logf != (FILE *)NULL)
fprintf(logf, "Incoming: %s %ld %lo %o\n",
name, Bytesleft, Modtime, Filemode);
#endif
}
#endif /* REMOTE */
}
else
{ /* File coming from CP/M system */
for (p=name; *p; ++p) /* change / to _ */
if ( *p == '/')
*p = '_';
if ( *--p == '.') /* zap trailing period */
*p = 0;
}
strcpy(Pathname, name);
#ifndef REMOTE
if (Verbose)
{
fprintf(STDERR, "Receiving %s %s [mode %s]\n\n",
name, Thisbinary?"BIN":"ASCII", openmode);
#ifdef RDEBUG
if(logf != (FILE *)NULL)
fprintf(logf, "Receiving %s %s %s\n",
name, Thisbinary?"BIN":"ASCII", openmode);
#endif
}
#endif /* REMOTE */
if ((fout=stfopen(name, openmode)) <= 0)
return ERROR;
return OK;
}
/*
* Putsec writes the n characters of buf to receive file fout.
* If not in binary mode, all characters
* starting with CPMEOF are discarded.
*/
putsec(buf, n)
unsigned char *buf;
register int n;
{
register unsigned char *p;
if (Thisbinary)
{
for (p=buf; --n>=0; p++ )
{
if(stputc( *p, fout) < 0)
{
fprintf(STDERR, "\r\nError while Writing file\n");
return ERROR;
}
}
}
else
{
if (Eofseen)
return OK;
for (p=buf; --n>=0; p++ )
{
if (*p == CPMEOF)
{
Eofseen=TRUE;
return OK;
}
if(*p == '\n')
{
if(stputc('\r' ,fout) < 0)
{
fprintf(STDERR, "\r\nError while Writing file\n");
return ERROR;
}
}
if(stputc(*p ,fout) < 0)
{
fprintf(STDERR,"\r\nError while Writing file\n");
return ERROR;
}
}
}
return OK;
}
/*
* Log an error only if high verbose
*/
/*VARARGS1*/
llog(s,p,u)
char *s;
int p, u;
{
if (Verbose < 3)
return;
#ifdef RDEBUG
fprintf(logf, "error %d: ", errors);
fprintf(logf, s, p, u);
#endif
fprintf(STDERR, "\nerror %d: ", errors);
fprintf(STDERR, s, p, u);
}
#ifndef STANDALONE
/*
* If called as rb use YMODEM protocol
*/
chkinvok(s)
char *s;
{
Progname = s;
if (s[0]=='r' && s[1]=='b')
Nozmodem = TRUE;
}
#endif
/*
* Initialize for Zmodem receive attempt, try to activate Zmodem sender
* Handles ZSINIT frame
* Return ZFILE if Zmodem filename received, -1 on error,
* ZCOMPL if transaction finished, else 0
*/
tryz()
{
register int n;
register int cmdzack1flg;
if (Nozmodem) /* Check for "rb" program name */
return 0;
for (n=Zmodem?10:5; --n>=0; )
{
/* Set buffer length (0) and capability flags */
stohdr(0L);
Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK; /* of course we can break */
zshhdr(tryzhdrtype, Txhdr);
/* zshhdr(Badclose?ZFERR:ZRINIT, Txhdr); */
again:
switch (zgethdr(Rxhdr, 0))
{
case ZRQINIT:
continue;
case ZEOF:
continue;
case TIMEOUT:
continue;
case ZFILE:
zconv = Rxhdr[ZF0];
zmanag = Rxhdr[ZF1];
ztrans = Rxhdr[ZF2];
tryzhdrtype = ZRINIT;
Badclose = FALSE;
if (zrdata(secbuf, KSIZE) == GOTCRCW)
return ZFILE;
zshhdr(ZNAK, Txhdr);
goto again;
case ZSINIT:
if (zrdata(Attn, ZATTNLEN) == GOTCRCW)
{
zshhdr(ZACK, Txhdr);
goto again;
}
zshhdr(ZNAK, Txhdr);
goto again;
case ZFREECNT:
stohdr(~0L);
zshhdr(ZACK, Txhdr);
goto again;
case ZCOMMAND:
cmdzack1flg = Rxhdr[ZF0];
if (zrdata(secbuf, KSIZE) == GOTCRCW)
{
if (cmdzack1flg & ZCACK1)
stohdr(0L);
else
stohdr((long)sys2(secbuf));
PURGELINE; /* dump impatient questions */
do {
zshhdr(ZCOMPL, Txhdr);
}
while (++errors<10 && zgethdr(Rxhdr,1) != ZFIN);
ackbibi();
if (cmdzack1flg & ZCACK1)
exec2(secbuf);
return ZCOMPL;
}
zshhdr(ZNAK, Txhdr); goto again;
case ZCOMPL:
goto again;
default:
continue;
case ZFIN:
ackbibi(); return ZCOMPL;
case ZCAN:
return ERROR;
}
}
return 0;
}
/*
* Receive 1 or more files with ZMODEM protocol
*/
rzfiles()
{
register int c;
for (;;) {
switch (c = rzfile()) {
case ZEOF:
case ZSKIP:
switch (tryz()) {
case ZCOMPL:
return OK;
default:
return ERROR;
case ZFILE:
break;
}
continue;
default:
return c;
case ERROR:
return ERROR;
}
}
}
/*
* Receive a file with ZMODEM protocol
* Assumes file name frame is in secbuf
*/
rzfile()
{
register int c, n;
long rxbytes;
extern void rd_time();
Eofseen=FALSE;
if (procheader(secbuf) == ERROR) {
return (tryzhdrtype = ZSKIP);
/* zshhdr(ZSKIP, Txhdr);
return ZSKIP; */
}
n = 10; rxbytes = 0L;
Supexec(rd_time);
start_time = pr_time;
for (;;)
{
stohdr(rxbytes);
zshhdr(ZRPOS, Txhdr);
nxthdr:
switch (c = zgethdr(Rxhdr, 0)) {
default:
vfile("rzfile: zgethdr returned %d", c);
return ERROR;
case ZNAK:
case TIMEOUT:
if ( --n < 0)
{
vfile("rzfile: zgethdr returned %d", c);
return ERROR;
}
case ZFILE:
zrdata(secbuf, KSIZE);
continue;
case ZEOF:
/* ++jrb */
if (rclhdr(Rxhdr) != rxbytes)
{
/*
* Ignore eof if it's at wrong place - force
* a timeout because the eof might have gone
* out before we sent our zrpos.
*/
errors = 0; goto nxthdr;
}
/* --jrb
if (rclhdr(Rxhdr) != rxbytes)
{
continue;
}
-- */
if (closeit(rxbytes))
{
tryzhdrtype = ZFERR;
Badclose = TRUE;
vfile("rzfile: closeit returned <> 0");
return ERROR;
}
vfile("rzfile: normal EOF");
return c;
case ERROR: /* Too much garbage in header search error */
if ( --n < 0)
{
vfile("rzfile: zgethdr returned %d", c);
return ERROR;
}
zmputs(Attn);
continue;
case ZDATA:
n = 10;
if (rclhdr(Rxhdr) != rxbytes)
{
zmputs(Attn);
continue;
}
moredata:
switch (c = zrdata(secbuf, KSIZE))
{
case ZCAN:
vfile("rzfile: zgethdr returned %d", c);
return ERROR;
case ERROR: /* CRC error */
if ( --n < 0)
{
vfile("rzfile: zgethdr returned %d", c);
return ERROR;
}
zmputs(Attn);
continue;
case TIMEOUT:
if ( --n < 0)
{
vfile("rzfile: zgethdr returned %d", c);
return ERROR;
}
continue;
case GOTCRCW:
if(putsec(secbuf, Rxcount) == ERROR)
return ERROR;
rxbytes += Rxcount;
lreport(rxbytes);
stohdr(rxbytes);
zshhdr(ZACK, Txhdr);
goto nxthdr;
case GOTCRCQ:
if(putsec(secbuf, Rxcount) == ERROR)
return ERROR;
rxbytes += Rxcount;
lreport(rxbytes);
stohdr(rxbytes);
zshhdr(ZACK, Txhdr);
goto moredata;
case GOTCRCG:
if(putsec(secbuf, Rxcount) == ERROR)
return ERROR;
rxbytes += Rxcount;
lreport(rxbytes);
goto moredata;
case GOTCRCE:
if(putsec(secbuf, Rxcount) == ERROR)
return ERROR;
rxbytes += Rxcount;
lreport(rxbytes);
goto nxthdr;
}
}
}
}
/*
* Send a string to the modem, processing for \336 (sleep 1 sec)
* and \335 (break signal)
*/
zmputs(s)
char *s;
{
register int c;
while (*s) {
switch (c = *s++) {
case '\336':
stsleep(1); continue;
case '\335':
sendbrk(); continue;
default:
sendline(c);
}
}
}
/*
* Close the receive dataset, return OK or ERROR
*/
closeit(rxbytes)
long rxbytes;
{
unsigned int timep[2];
long end_time;
extern void rd_time();
if (stfclose(fout) != 0) {
fprintf(STDERR, "\r\nfile close ERROR\n");
return ERROR;
}
fout = (-1);
Supexec(rd_time);
end_time = pr_time;
if (Modtime) {
unix2st(Modtime, &timep[0], &timep[1]);
touch(Pathname, timep);
}
/* if it is read only by owner on remote, then it is set
* to read only on the ST, all other file modes are
* irrelevant.
*/
if (Filemode)
{
unsigned int fmode;
fmode = (unsigned int)(Filemode & 000777);
if( ((fmode & 0200) == 0) && ((fmode & 0400) != 0) )
{
/* it is readonly by owner on the remote, so
* make it read only on the ST too
*/
Fattrib(Pathname, 1, 0x01);
}
}
#ifndef REMOTE
if(rxbytes != 0L)
fprintf(STDERR,"\n\n%s Closed\nTransfer Time %ld secs.\tfor %ld bytes\
\tApprox %ld cps\n\n", Pathname, (end_time - start_time)/200L, rxbytes,
rxbytes/((end_time - start_time)/200L));
else
fprintf(STDERR,"\n\n%s Closed\n\n", Pathname);
#endif
lsct = 1;
return OK;
}
/*
* Ack a ZFIN packet, let byegones be byegones
*/
ackbibi()
{
register int n;
vfile("ackbibi:");
Readnum = 1;
stohdr(0L);
for (n=4; --n>=0; )
{
zshhdr(ZFIN, Txhdr);
for (;;) {
switch (readline(100))
{
case 'O':
readline(1); /* Discard 2nd 'O' */
/* ***** FALL THRU TO ***** */
case TIMEOUT:
vfile("ackbibi complete");
return;
default:
break;
}
}
}
}
/*
* Strip leading ! if present, do shell escape.
*/
sys2(s)
register char *s;
{
if (*s == '!')
++s;
return stsystem(s);
}
/*
* Strip leading ! if present, do exec.
*/
exec2(s)
char *s;
{
/** Are you kidding
if (*s == '!')
++s;
mode(0);
execl("/bin/sh", "sh", "-c", s);
**/
}
/*
* Touch a file
*/
#ifndef MANX
#undef Fdatime /* There exist brain damaged versions of osbind.h */
#define Fdatime(a,b,c) gemdos(0x57,a,b,c)
#endif /* MANX has its _Gemdos stuff */
touch(name, timep)
char *name;
unsigned int *timep;
{
register int handl;
if((handl = Fopen(name, 0)) < 0)
{
#ifndef REMOTE
fprintf(STDERR,"*WARNING* Could not set file modification time for %s\n",
name);
#endif
return;
}
Fdatime(timep, handl, 1);
Fclose(handl);
}
/* -eof- */